//
// ********************************************************************
// * License and Disclaimer                                           *
// *                                                                  *
// * The  Geant4 software  is  copyright of the Copyright Holders  of *
// * the Geant4 Collaboration.  It is provided  under  the terms  and *
// * conditions of the Geant4 Software License,  included in the file *
// * LICENSE and available at  http://cern.ch/geant4/license .  These *
// * include a list of copyright holders.                             *
// *                                                                  *
// * Neither the authors of this software system, nor their employing *
// * institutes,nor the agencies providing financial support for this *
// * work  make  any representation or  warranty, express or implied, *
// * regarding  this  software system or assume any liability for its *
// * use.  Please see the license in the file  LICENSE  and URL above *
// * for the full disclaimer and the limitation of liability.         *
// *                                                                  *
// * This  code  implementation is the result of  the  scientific and *
// * technical work of the GEANT4 collaboration.                      *
// * By using,  copying,  modifying or  distributing the software (or *
// * any work based  on the software)  you  agree  to acknowledge its *
// * use  in  resulting  scientific  publications,  and indicate your *
// * acceptance of all terms of the Geant4 Software license.          *
// ********************************************************************
//
//
/// \file B1/src/DetectorConstruction.cc
/// \brief Implementation of the B1::DetectorConstruction class

#include "DetectorConstruction.hh"

#include "G4Box.hh"            // 包含在实体定义时所使用的形状：长方体
#include "G4Cons.hh"           // a Phi segment of a cone
#include "G4LogicalVolume.hh"  //包含逻辑几何体
#include "G4NistManager.hh"    //包含在材料种类定义时所使用的数据库
#include "G4PVPlacement.hh"    //包含物理几何体(G4PVPlacement类)
#include "G4SystemOfUnits.hh"  //包含物理单位制
#include "G4Trd.hh"

namespace B1
{

    //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

    G4VPhysicalVolume* DetectorConstruction::Construct()
    {
        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Get nist material manager
        G4NistManager* nist = G4NistManager::Instance();

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Envelope parameters
        G4double env_sizeXY = 20 * cm, env_sizeZ = 30 * cm;
        G4Material* env_mat = nist->FindOrBuildMaterial("G4_WATER");

        // Option to switch on/off checking of volumes overlaps
        G4bool checkOverlaps = true;

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx word
        G4double world_sizeXY = 1.2 * env_sizeXY;
        G4double world_sizeZ = 1.2 * env_sizeZ;
        G4Material* world_mat = nist->FindOrBuildMaterial("G4_AIR");

        auto solidWorld = new G4Box("World",                                                     // its name
                                    0.5 * world_sizeXY, 0.5 * world_sizeXY, 0.5 * world_sizeZ);  // its size

        auto logicWorld = new G4LogicalVolume(  //
            solidWorld,                         // its solid; 指定依赖的实体
            world_mat,                          // its material; 指定材料的种类
            "World",                            // its name; 名称
            nullptr,                            //; 指定所在磁场的状况，默认为没有磁场
            nullptr,  //指定是否为探测器的一部分，默认不是; 如果指定其为探测器的一部分，则可以在SteppingAction中获取粒子在该部位相互作用的信息
            nullptr,  //指定是否应用用户自定义限制; 用户自定义限制是指, 用户自行设置的 关于粒子在逻辑几何体中的最大步长 等逻辑几何体属性的设置
            true      //指定是否开启优化，默认开启; 此处的优化指的是, Geant4在处理粒子 在逻辑几何体中的track时 将几何体体素化的方法
        );

        ///它不依附于任何母体，本身为Geant4中的World. 这种不依附任何母体的World应该有且仅有一个。
        auto physWorld = new G4PVPlacement(nullptr,          // no rotation; 指定该物理几何体的旋转情况
                                           G4ThreeVector(),  // at (0,0,0); 指定该物理几何体在母几何体中的相对位置
                                           logicWorld,       // its logical volume; 指定其依赖的逻辑几何体
                                           "World",          // its name;  名称
                                           nullptr,          // its mother volume; 指定其所在的母几何体，注意这里必须指定一个逻辑几何体
                                           false,            // 是否含有布尔操作; 有些实体较复杂，是由若干个简单实体通过叠加或相减形成的，称为布尔操作
                                           0,                // copy number; 给这个物理几何体分配一个代号
                                           checkOverlaps     // overlaps checking; 指定是否检查有无重叠部分，一般应设置为true
        );

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Envelope
        auto solidEnv = new G4Box("Envelope",                                            // its name
                                  0.5 * env_sizeXY, 0.5 * env_sizeXY, 0.5 * env_sizeZ);  // its size

        auto logicEnv = new G4LogicalVolume(solidEnv,     // its solid
                                            env_mat,      // its material
                                            "Envelope");  // its name
        //创建一个物理几何体，名称为"Envelope"，其逻辑几何体为"logicWorld"，依附于逻辑几何体"logicWorld",即依附于 World
        new G4PVPlacement(nullptr,          // no rotation
                          G4ThreeVector(),  // at (0,0,0)
                          logicEnv,         // its logical volume
                          "Envelope",       // its name
                          logicWorld,       // its mother  volume
                          false,            // no boolean operation
                          0,                // copy number; 给这个物理几何体分配一个代号
                          checkOverlaps     // overlaps checking
        );

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Shape 1
        G4Material* shape1_mat = nist->FindOrBuildMaterial("G4_A-150_TISSUE");
        G4ThreeVector pos1 = G4ThreeVector(0, 2 * cm, -7 * cm);

        // Conical section shape
        G4double shape1_rmina = 0. * cm, shape1_rmaxa = 2. * cm;
        G4double shape1_rminb = 0. * cm, shape1_rmaxb = 4. * cm;
        G4double shape1_hz = 3. * cm;
        G4double shape1_phimin = 0. * deg, shape1_phimax = 360. * deg;
        auto solidShape1 = new G4Cons("Shape1",                                                //
                                      shape1_rmina, shape1_rmaxa, shape1_rminb, shape1_rmaxb,  //
                                      shape1_hz, shape1_phimin, shape1_phimax                  //
        );

        auto logicShape1 = new G4LogicalVolume(solidShape1,  // its solid
                                               shape1_mat,   // its material
                                               "Shape1");    // its name

        new G4PVPlacement(nullptr,         // no rotation
                          pos1,            // at position
                          logicShape1,     // its logical volume
                          "Shape1",        // its name
                          logicEnv,        // its mother  volume
                          false,           // no boolean operation
                          0,               // copy number; 给这个物理几何体分配一个代号
                          checkOverlaps);  // overlaps checking

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Shape 2
        G4Material* shape2_mat = nist->FindOrBuildMaterial("G4_BONE_COMPACT_ICRU");
        G4ThreeVector pos2 = G4ThreeVector(0, -1 * cm, 7 * cm);

        // Trapezoid shape
        G4double shape2_dxa = 12 * cm, shape2_dxb = 12 * cm;
        G4double shape2_dya = 10 * cm, shape2_dyb = 16 * cm;
        G4double shape2_dz = 6 * cm;
        auto solidShape2 = new G4Trd("Shape2",  // its name
                                     0.5 * shape2_dxa, 0.5 * shape2_dxb, 0.5 * shape2_dya, 0.5 * shape2_dyb,
                                     0.5 * shape2_dz);  // its size

        auto logicShape2 = new G4LogicalVolume(solidShape2,  // its solid
                                               shape2_mat,   // its material
                                               "Shape2");    // its name

        new G4PVPlacement(nullptr,         // no rotation
                          pos2,            // at position
                          logicShape2,     // its logical volume
                          "Shape2",        // its name
                          logicEnv,        // its mother  volume
                          false,           // no boolean operation
                          0,               // copy number
                          checkOverlaps);  // overlaps checking

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Set Shape2 as scoring volume
        _fScoringVolume = logicShape2;

        ///xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx always return the physical World
        return physWorld;
    }

    //....oooOO0OOooo........oooOO0OOooo........oooOO0OOooo........oooOO0OOooo......

}  // namespace B1
